package gr.uoa.di.thanos.botcraft;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.nio.IntBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.lwjgl.BufferUtils;
import org.lwjgl.opencl.CLBuildProgramCallback;
import org.lwjgl.opencl.CLContext;
import org.lwjgl.opencl.CLDevice;
import org.lwjgl.opencl.CLProgram;
import org.lwjgl.opencl.Util;

import static org.lwjgl.opencl.CL10.*;

public class OpenCLUtils {	
	private static final int BUFFER_SIZE = 1024;
	private static final Logger LOGGER = Logger.getLogger(OpenCLUtils.class.getName());

	public static CLProgram compileCL(final String resource, final CLContext context, final CLDevice device) {
		final IntBuffer status = BufferUtils.createIntBuffer(1);
		try {
			final CLProgram program = clCreateProgramWithSource(context, OpenCLUtils.loadProgram(resource), status);
			Util.checkCLError(status.get(0));
			clBuildProgram(program, device, "", new CLBuildProgramCallback() {
				@Override
				protected void handleMessage(final CLProgram program) {
					switch (program.getBuildInfoInt(device, CL_PROGRAM_BUILD_STATUS)) {
					case CL_BUILD_ERROR:
						LOGGER.log(Level.WARNING, "Error compiling CL program " + resource + ":error building program\n" + program.getBuildInfoString(device, CL_PROGRAM_BUILD_LOG));
						break;
					case CL_BUILD_SUCCESS:
						LOGGER.info("CL program " + resource + " compiled successfully");
					}
				}
			});
			return program;
		} catch (final IOException e) {
			LOGGER.log(Level.WARNING, "Error compiling CL program " + resource + ": error loading program", e);
			return null;
		}
	}
	
	private static String loadProgram(final String resource) throws IOException {
		final InputStreamReader input = new InputStreamReader(OpenCLUtils.class.getResourceAsStream(resource));
		try {
			final StringWriter output = new StringWriter();
			final char[] buffer = new char[BUFFER_SIZE];
			int read = 0;
			while ((read = input.read(buffer)) > 0)
				output.write(buffer, 0, read);
			return output.toString();
		} finally {
			input.close();
		}
	}
}
